package control

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log/slog"
	"rule/cache"
	"rule/model"
	"rule/pkg/gwprop"
	"rule/pkg/snowflake"
	"strconv"
	"time"
)

const ctrl_ptid_prefix string = "ctrl:ptid:"

func ReverseCtrl(id, ruleId string, ts, delaySec int64, linkageList []model.LinkagePoint) {
	_data := make([]model.ReverseDataStruct, 0)
	for _, _linkage := range linkageList {
		_val1, err1 := calcLinkageVal(_linkage.PtId, _linkage.SetPointOperator, _linkage.SetPointValue)
		if err1 != nil {
			slog.Error("反控异常calcLinkageVal_err:" + err1.Error())
			continue
		}
		var reverseDataStruct model.ReverseDataStruct
		reverseDataStruct.CInsId = strconv.Itoa(_linkage.CInsId)
		reverseDataStruct.PtInsId = strconv.Itoa(_linkage.PtInsId)
		reverseDataStruct.PtId = _linkage.PtId
		reverseDataStruct.Addr = _linkage.Addr
		reverseDataStruct.Retry = strconv.Itoa(_linkage.Retry)
		reverseDataStruct.OnErr = _linkage.OnErr
		reverseDataStruct.Val = _val1
		_data = append(_data, reverseDataStruct)
	}

	// 读取数据
	if len(_data) == 0 {
		linkageList = nil
		return
	}

	// 构造反控的json struct
	reverseCtrl := newCommonReverseDataStruct(ruleId, ts, delaySec, _data)
	//
	go sendReverseCtrlJson(id, ruleId, reverseCtrl)
}

func sendReverseCtrlJson(id, ruleId string, reverseCtrl *model.ReverseCtrlStruct) {
	//
	buf, _ := json.Marshal(reverseCtrl)
	reverseCtrl = nil
	bufString := string(buf) // bytesconv.BytesToString(buf)
	// PUBLISH rule.engine.ctrl
	slog.Warn("反控执行", "id", id, "rule_id", ruleId, "json_data", bufString)
	cache.Rdb0.Publish(context.Background(), "rule.engine.ctrl", bufString)
}

func calcLinkageVal(ptId string, linkageOpt model.PointOperator, linkageValue float64) (string, error) {
	if linkageOpt == model.OptEQ {
		// 如果需要保留2位小数, 就把-1改成2
		_v := strconv.FormatFloat(linkageValue, 'f', -1, 64)
		return _v, nil
	}

	// 读取redis
	strCmd := cache.Rdb0.HGet(context.Background(), ctrl_ptid_prefix+ptId, "v")
	if strCmd.Err() != nil {
		return "", errors.New(fmt.Sprintf("redis未读取到ptid:%s,err:%v", ptId, strCmd.Err()))
	}

	// redis 的value string转成float
	oldValStr := strCmd.Val()
	oldFloat, err := strconv.ParseFloat(oldValStr, 64)
	if err != nil {
		return "", errors.New(fmt.Sprintf("取到ptid:%s,valstr:%s,err:%v", ptId, oldValStr, err))
	}

	var newFloat float64
	if linkageOpt == model.OptPLUS {
		newFloat = oldFloat + linkageValue
		slog.Info(fmt.Sprintf("pt_id_%s_联动计算: %v + %v = %v", ptId, oldFloat, linkageValue, newFloat))
	} else if linkageOpt == model.OptMINUS {
		newFloat = oldFloat - linkageValue
		slog.Info(fmt.Sprintf("pt_id_%s_联动计算: %v - %v = %v", ptId, oldFloat, linkageValue, newFloat))
	} else if linkageOpt == model.OptMULTIPLY {
		newFloat = oldFloat * linkageValue
		slog.Info(fmt.Sprintf("pt_id_%s_联动计算: %v * %v = %v", ptId, oldFloat, linkageValue, newFloat))
	} else if linkageOpt == model.OptDIVIDE {
		newFloat = oldFloat / linkageValue
		slog.Info(fmt.Sprintf("pt_id_%s_联动计算: %v / %v = %v", ptId, oldFloat, linkageValue, newFloat))
	}

	var newValStr string
	if newFloat == float64(int64(newFloat)) {
		newValStr = strconv.FormatInt(int64(newFloat), 10)
	} else {
		// 保留两位小数
		newValStr = strconv.FormatFloat(newFloat, 'f', 2, 64)
	}
	return newValStr, nil
}

func newCommonReverseDataStruct(_ruleId string, ts, delaySec int64, _data []model.ReverseDataStruct) *model.ReverseCtrlStruct {
	// 规则id_10位时间戳-雪花id
	reqId := fmt.Sprintf("%s_%d-%d-%d", _ruleId, ts, delaySec, snowflake.GetIdUInt64())
	return &model.ReverseCtrlStruct{
		Type:    "W",
		Time:    time.Now().UnixMilli(),
		Timeout: 120,
		ReqId:   reqId,
		GwId:    gwprop.GetProp().GWID,
		RuleId:  _ruleId,
		Data:    _data,
	}
}
